<template>
  <div class="role-container">
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>权限管理</el-breadcrumb-item>
      <el-breadcrumb-item>角色列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片区域 -->
    <el-card class="box-card">
      <!-- 栅格+按钮 -->
      <el-row>
        <el-col>
          <el-button type="info">添加角色</el-button>
        </el-col>
      </el-row>
      <!-- 角色列表表格 -->
      <el-table :data="rolesList" stripe border>
        <!-- 展开行 -->
        <!-- 该展开列语句会为后续每一个索引列添加一个下拉展开列 -->
        <el-table-column type="expand">
          <!-- 如果为展开列添加作用域插槽，那么传入的数据就是表格单向绑定的data属性的数据
            这个数据对象中的row就是对应每一行的数据 -->
            <!-- for循环渲染三级权限按钮，套用栅格布局，一级权限按钮5列，二级和三级共分19列
              因为采用了栅格布局，故再el-row组件中进行循环 -->
          <template slot-scope="scope">
            <el-row v-for="(item, i1) in scope.row.children" :key="item.id" :class="['flex-align-center','bottom-line', i1 === 0? 'top-line': '']">
              <!-- 一级权限按钮 -->
              <el-col :span="4" :offset="2">
                <!-- 动态绑定类，都有底框，如果索引为零则加上顶框 -->
                <el-tag>{{item.authName}}</el-tag>
                <i class="el-icon-caret-right"></i>
              </el-col>
              <el-col :span="16" :offset="2">
                <el-row v-for="(second, i2) in item.children" :key="second.id" :class="['flex-align-center', i2 === 0? '': 'top-line']">
                  <!-- 二级权限按钮 -->
                  <el-col :span="6">
                    <el-tag type="success">{{second.authName}}</el-tag>
                    <i class="el-icon-caret-right"></i>
                  </el-col>
                  <!-- 三级权限按钮 -->
                  <el-col :span="10">
                    <el-tag closable
                      type="warning"
                      v-for="third in second.children"
                      :key="third.id"
                      @close="closeTag(scope.row.id, third.id)">{{third.authName}}
                    </el-tag>
                  </el-col>
                </el-row>
              </el-col>
            </el-row>
          </template>
        </el-table-column>
        <!-- 索引列 -->
        <el-table-column type="index" label="#"></el-table-column>
        <el-table-column label="角色名称" prop="roleName"></el-table-column>
        <el-table-column label="角色描述" prop="roleDesc"></el-table-column>
        <el-table-column label="操作" width="300">
          <template slot-scope="scope">
            <el-button type="primary" round icon="el-icon-edit" size="mini">编辑</el-button>
            <el-button type="danger" round icon="el-icon-delete" size="mini">删除</el-button>
            <el-button type="warning" round icon="el-icon-setting" size="mini" @click="showRightsDialog(scope.row)">修改权限</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <!-- 修改权限对话框，默认隐藏，通过点击修改权限按钮显示 -->
    <el-dialog
      title="修改权限"
      :visible.sync="rightDialogVisible"
      width="50%"
      @close="closeRightsDialog">
      <!-- 树型控件展示权限列表
        props树型用于指定树形控件的拓扑规则，
        node-key属性用于指定每个节点的唯一标识符，
        default-checked-keys用于指定默认选中的选项的键值构成的数组 -->
        <el-tree :data="rightsList" :props="rightsTreeProps"
          show-checkbox node-key="id" :default-checked-keys="rightsChecked"
          default-expand-all ref="rightsTreeRef"></el-tree>
        <span slot="footer" class="dialog-footer">
          <el-button @click="rightDialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="allotRights">确 定</el-button>
        </span>
    </el-dialog>
  </div>
</template>

<script>
import { getRolesList } from '@/api/getRolesApi.js'
import { deleteRights } from '@/api/deleteRightsApi.js'
import { getRightsList } from '@/api/getRightsListApi.js'
import { allotRights } from '@/api/allotRightsApi.js'
export default {
  name: 'myRoles',
  data () {
    return {
      // 角色列表，它的第一层children数组中存放着该角色的权限列表
      rolesList: [],
      // 对话框可见属性的控制变量
      rightDialogVisible: false,
      // 树型权限列表
      rightsList: [],
      // 树型控件拓扑规则
      rightsTreeProps: {
        label: 'authName',
        children: 'children'
      },
      // 默认勾选的三级权限id数组
      rightsChecked: [],
      // 当前角色id，用于发送post请求授权角色权限
      tmpId: ''
    }
  },
  methods: {
    // 获取角色列表
    async getRolesData () {
      const { data: res } = await getRolesList()
      if (res.meta.status !== 200) {
        return this.$notify.error({ title: '角色列表获取失败', message: res.meta.msg })
      }
      // 没有返回出去说明请求成功，将后台角色列表数据赋给vue实例中的rolesList数组
      this.rolesList = res.data
    },
    // 删除某角色三级权限的确认弹窗函数
    async closeTag (roleId, rightId) {
      const result = await this.$confirm('执行此操作将删除当前角色的本项权限, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(err => err)

      if (result !== 'confirm') {
        return this.$notify.info({ title: '删除操作取消' })
      }
      const { data: res } = await deleteRights(roleId, rightId)
      if (res.meta.status !== 200) {
        return this.$notify.error({ title: '删除权限失败', message: res.meta.msg })
      }
      // 重新调用getRoleList请求新的权限列表
      this.getRolesData()
      this.$notify({ title: '删除权限成功' })
      console.log(res)
    },
    // 修改权限对话框的点击事件监听函数
    async showRightsDialog (row) {
      // 获取树型权限列表
      const { data: res } = await getRightsList('tree')
      if (res.meta.status !== 200) {
        return this.$notify({ title: '获取权限列表失败', message: res.meta.msg })
      }
      // 没有return出去说明请求成功，将数据存入rightsList数组中
      this.rightsList = res.data
      // 获取到总权限列表后，需要得到角色列表中需要勾选的权限
      // 点击事件调用函数时传入当前的角色的对象，它的children数组存放着这个角色的所有权限
      // 递归调用这个角色对象就可以得到该角色所有的三级权限
      this.recursForThirdRightsId(row, this.rightsChecked)
      // 在这里获取当前角色id，提供给后续确认按钮的事件监听函数使用
      this.tmpId = row.id
      this.rightDialogVisible = true
    },

    // 用于查询某角色权限三级节点id的递归函数
    recursForThirdRightsId (node, arry) {
      if (!node.children) {
        return arry.push(node.id)
      }
      // 没有返回出去说明不是三级节点，那么这个节点必然含有存放下一级节点的children数组
      // 这时循环遍历该节点的children数组，每个children都调用一次本函数，直到return出去
      // 这时数组中存放的就是全部三级节点的id
      node.children.forEach(element => {
        this.recursForThirdRightsId(element, arry)
      })
    },
    // 修改权限对话框的关闭事件的监听函数
    closeRightsDialog () {
      // 当关闭对话框时，清空预勾选三级权限数组的元素，
      // 防止上一个角色的权限叠加到下一个角色的修改权限对话框中
      this.rightsChecked = []
    },
    // 修改权限弹框的确定按钮的单击事件监听函数
    async allotRights () {
      // 确定后先拿到所有的三级权限、二级权限、一级权限的id
      // 使用tree组件提供的方法获取id，此时需要给tree组件绑定引用
      const allId = [...this.$refs.rightsTreeRef.getCheckedKeys(), ...this.$refs.rightsTreeRef.getHalfCheckedKeys()]
      // 后端接口要求post传递参数为逗号分隔的字符串，使用join函数拼接
      const idString = allId.join(',')
      // 在这里调用导入的授权函数，其中第一个参数是vue实例身上挂载的从打开本对话框的事件监听函数中获取到的临时角色Id
      // 第二个参数是拼接好的权限id字符串
      const { data: res } = await allotRights(this.tmpId, idString)
      if (res.meta.status !== 200) {
        return this.$notify.error({ title: '授权失败', message: res.meta.msg })
      }
      // 没有return出去说明授权成功，重新请求用户权限并弹出提示
      this.getRolesData()
      this.$notify.success({ title: '授权成功' })
      // 授权完成后关闭对话框
      this.rightDialogVisible = false
    }
  },
  created () {
    this.getRolesData()
  }
}
</script>

<style lang="less" scoped>
  .el-table--border {
    margin-top: 20px;
  }
  .el-col {
    align-items: center;
  }
  .el-tag {
    margin: 7px;
  }
  .bottom-line {
    border-bottom: solid 1px #e6e6e6;
  }
  .top-line {
    border-top: solid 1px #e6e6e6;
  }
</style>
